/*
 * qv_geneticEnvironment.c
 */

#include "qv_geneticEnvironment.h"
#include "qv_utils.h"
#include "qv_fileIO.h"
#include "qv_testEnvironment.h"


/*
 * Called from game/g_main.c/G_InitGame().
 * Initializes the variables and the bots for the game.
 */
void qv_initEnvironment(void) {	
	int i;
	int roundNum;
	char **botNames = malloc(sizeof(char*) * getSettings()->bots);
	char *botName;

	/* Check if testmode is on, if so go to testEnvironment */
	if (getSettings()->testmode) {
		initTestEnvironment();
		return;
	}

	roundNum = readRoundNum();
	switch (roundNum) {
		case 0:
			/* Com_Printf("\n\n^4  <-------> INITIALIZING QV ENVIRONMENT <------->\n"); */

			/*
			 * during initial round (0), completely random bots must be generated
			 * and added to bot database so genetic algorithm can start properly
			 * (bots generated here cannot yet be loaded ingame so round 0 just
			 * serves as setup)
			 */
			for(i = 0; i < getSettings()->bots; i++) {
				botNames[i] = generateBotName(roundNum + 1, QV_RANDOM_BOT_STR, (i+1));
			}
			generateRandomGenes(roundNum + 1, botNames);
			startNextRound(roundNum);
			
			for(i = 0; i < getSettings()->bots; i++) {
				free(botNames[i]);
			}			
			break;

		case 1:
			/* spawn bots generated in dummy setup round */
			for(i = 0; i < getSettings()->bots; i++) {
				botName = generateBotName(roundNum, QV_RANDOM_BOT_STR, (i+1));
				spawnBot(botName);
				free(botName);
			}
			break;

		default:
			/*
			 * child bots generated at end of previous round must be spawned
			 * here since Quake does not know about any new bots.txt aliases 
			 * until start of next round
			 */
			for(i = 0; i < getSettings()->bots; i++) {
				botName = generateBotName(roundNum, QV_CHILD_BOT_STR, (i+1));
				spawnBot(botName);
				free(botName);
			}
			break;
	}
	
	trap_SendConsoleCommand(EXEC_APPEND, "team spectator\n");
	trap_SendConsoleCommand(EXEC_APPEND, "bot_nochat 1\n");
	free(botNames);
	freeSettings();
}

void generateRandomGenes(int roundNum, char **botNames) {		
	QV_genData *genData = malloc(sizeof(struct QV_genData) * getSettings()->bots);
	
	int i;
	for (i = 0; i < getSettings()->bots; i++) {
		/* Generate random unnormalized base gen data */
		generateRandomGens(genData, i, botNames[i]);

		/* Generate random unnormalized item weight gen data */
		generateRandomItemWeigths(genData, i);

		/* Set fixed file gens to right filename */
		setFixedFileGens(botNames[i], i, genData);

		strcpy(genData[i].parent1, "none");
		strcpy(genData[i].parent2, "none");
	}

	/* Write the ai files */
	writeNewBotFiles(genData);

	/* Store genes */
	writeGenData(roundNum, genData);

	free(genData);
}


/*
 * restarts map when round over until max rounds
 * reached (done via file IO since restart causes
 * qagame.so to be reloaded and resets all global
 * vars), called from LogExit()
 */
void startNextRound(int roundNum) {
	char *mapReloadStr = malloc(sizeof(char) * LINE_BUF_SIZE);
	char *mapName = malloc(sizeof(char) * LINE_BUF_SIZE);
	int testMode = getSettings()->testmode;

	if ((testMode && roundNum < getSettings()->testrounds) || 
		(!testMode && roundNum < getSettings()->maxrounds)) {
		writeRoundNum(++roundNum);

		mapName[0] = '\0';
		trap_Cvar_VariableStringBuffer("mapname", mapName, LINE_BUF_SIZE);
		
		sprintf(mapReloadStr, "map %s\n", mapName);
		trap_SendConsoleCommand(EXEC_APPEND, mapReloadStr);
	}

	free(mapReloadStr);
	free(mapName);
}

/*
 * spawns bot with name <botName> 
 */
void spawnBot(char* botName) {
	char *addBotStr = malloc(sizeof(char) * LINE_BUF_SIZE);
	
	sprintf(addBotStr, "addbot %s %s QV 50 %s\n", botName, QV_BOT_SKILL_LVL, botName);
	trap_SendConsoleCommand(EXEC_APPEND, "wait 5\n");
	trap_SendConsoleCommand(EXEC_APPEND, addBotStr);
	free(addBotStr);
}

/*
 * kicks all current bots from the game
 */
void kickBots(gclient_t* clients) {
	int i;
	for (i = 0; i < getSettings()->bots; i++) {
		/* Start at index 1, leaving the spectating player */
		trap_BotFreeClient(clients[i+1].ps.clientNum);
	}
}
